﻿using Cysharp.Threading.Tasks;
using DG.Tweening;
using UnityEngine;

/// <summary>
/// UI基类
/// </summary>
public abstract class UIPanelBase : UIBehaviour
{
    [SerializeField]
    public UIPanelType type = UIPanelType.Normal;
    [SerializeField]
    protected UIShowAnimaMode showAnimaMode = UIShowAnimaMode.Default;
    [SerializeField]
    protected RectTransform animaWindow;
    [SerializeField]
    protected float animaDuration = 0.35f;

    /// <summary>
    /// 用于界面暂停时阻挡界面
    /// </summary>
    [HideInInspector]
    public GameObject mask;

    private string m_UIName;
    public string uiName => m_UIName ?? (m_UIName = GetType().Name);

    public bool active => gameObject.activeSelf;

    #region 生命周期函数，由 UIManager 统一调用

    /// <summary>
    /// 初始化
    /// </summary>
    protected virtual void OnInit() { }

    /// <summary>
    /// 显示时
    /// </summary>
    protected virtual void OnShow() { }

    /// <summary>
    /// 隐藏时
    /// </summary>
    protected virtual void OnHide() { }

    /// <summary>
    /// 暂停时，界面停止更新显示停止接收消息
    /// </summary>
    protected virtual void OnPause() { }

    /// <summary>
    /// 从界面暂停中恢复时
    /// </summary>
    protected virtual void OnResume() { }

    /// <summary>
    /// 成为交点时
    /// </summary>
    protected virtual void OnFocus() { }

    /// <summary>
    /// 卸载时
    /// </summary>
    protected virtual void OnRelease() { }

    #endregion 生命周期函数，由 UIManager 统一调用

    #region UI显示动画回调

    /// <summary>
    /// 显示动画开始时，用于界面表现逻辑处理
    /// </summary>
    protected virtual UniTask OnShowingStart() => UniTask.CompletedTask;

    /// <summary>
    /// 显示动画结束时，用于界面表现逻辑处理
    /// </summary>
    protected virtual UniTask OnShowingEnd() => UniTask.CompletedTask;

    /// <summary>
    /// 隐藏动画开始时，用于界面表现逻辑处理
    /// </summary>
    protected virtual UniTask OnHidingStart() => UniTask.CompletedTask;

    /// <summary>
    /// 隐藏动画结束时，用于界面表现逻辑处理
    /// </summary>
    protected virtual UniTask OnHidingEnd() => UniTask.CompletedTask;

    #endregion UI显示动画回调

    #region 公开方法

    public void Init()
    {
        OnInit();
    }

    /// <summary>
    /// 显示界面
    /// </summary>
    public async void Show()
    {
        if (active) return;

        gameObject.SetActive(true);
        transform.SetAsLastSibling();
        rectTransform.Stretch();
        OnShow();
        await PlayShowingTween();

        Debug.Log($"UIPanelBase 界面显示成功：{uiName}");
    }

    /// <summary>
    /// 隐藏界面
    /// </summary>
    public async void Hide()
    {
        if (!active) return;

        await PlayHidingTween();
        OnHide();
        gameObject.SetActive(false);

        Debug.Log($"UIPanelBase 界面隐藏成功：{uiName}");
    }

    /// <summary>
    /// 界面开关切换
    /// </summary>
    public void Switch()
    {
        if (active)
            Hide();
        else
            Show();
    }

    /// <summary>
    /// 设为焦点
    /// </summary>
    public void FocusOn()
    {
        if (!active) return;
        transform.SetAsLastSibling();
        Debug.Log($"UIPanelBase 界面焦点设置成功：{uiName}");
        OnFocus();
    }

    /// <summary>
    /// 暂停界面
    /// </summary>
    public void Pause()
    {
    }

    /// <summary>
    /// 恢复界面暂停
    /// </summary>
    public void Resume()
    {
    }

    #endregion 显示隐藏自调用封装

    #region 内部方法

    // 播放界面打开动画
    private async UniTask PlayShowingTween()
    {
        await OnShowingStart();
        switch (showAnimaMode)
        {
            case UIShowAnimaMode.Fade:
                {
                    animaWindow.gameObject.SetActive(true);
                    var cg = animaWindow.CheckComponent<CanvasGroup>();
                    cg.blocksRaycasts = true;
                    cg.DOKill();
                    await cg.DOFade(1, animaDuration).ChangeStartValue(0f).ToUniTask();
                }
                break;
            case UIShowAnimaMode.Popup:
                {
                    animaWindow.gameObject.SetActive(true);
                    var tweenScale = animaWindow.DOScale(1, animaDuration).ChangeStartValue(Vector3.one * 0.5f).SetEase(Ease.OutBack);
                    var cg = animaWindow.CheckComponent<CanvasGroup>();
                    cg.blocksRaycasts = true;
                    cg.DOKill();
                    var tweenFade = cg.DOFade(1, animaDuration).ChangeStartValue(0f);
                    await UniTask.WhenAll(tweenScale.ToUniTask(), tweenFade.ToUniTask());
                }
                break;
        }
        await OnShowingEnd();
    }

    // 播放界面关闭动画
    private async UniTask PlayHidingTween()
    {
        await OnHidingStart();
        switch (showAnimaMode)
        {
            case UIShowAnimaMode.Fade:
                {
                    var cg = animaWindow.CheckComponent<CanvasGroup>();
                    cg.blocksRaycasts = false;
                    cg.DOKill();
                    await cg.DOFade(0, animaDuration).ChangeStartValue(1f).ToUniTask();
                    animaWindow.gameObject.SetActive(false);
                }
                break;
            case UIShowAnimaMode.Popup:
                {
                    animaWindow.DOKill();
                    var tweenScale = animaWindow.DOScale(0.5f, animaDuration).ChangeStartValue(Vector3.one).SetEase(Ease.InBack);
                    var cg = animaWindow.CheckComponent<CanvasGroup>();
                    cg.blocksRaycasts = false;
                    cg.DOKill();
                    var tweenFade = cg.DOFade(0, animaDuration).ChangeStartValue(1f);
                    await UniTask.WhenAll(tweenScale.ToUniTask(), tweenFade.ToUniTask());
                    animaWindow.gameObject.SetActive(false);
                }
                break;
        }
        await OnHidingEnd();
    }

    #endregion 
}

/// <summary>
/// 面板类型
/// </summary>
public enum UIPanelType
{
    /// <summary>
    /// 常驻/固定
    /// </summary>
    Fixed,
    /// <summary>
    /// 普通
    /// </summary>
    Normal,
    /// <summary>
    /// 全屏
    /// </summary>
    FullScreen,
    /// <summary>
    /// 弹窗
    /// </summary>
    Popup,
    /// <summary>
    /// 格挡
    /// </summary>
    Block
}

/// <summary>
/// 显示动画模式
/// </summary>
public enum UIShowAnimaMode
{
    /// <summary>
    /// 默认，无动画
    /// </summary>
    Default,
    /// <summary>
    /// 淡入淡出
    /// </summary>
    Fade,
    /// <summary>
    /// 弹出
    /// </summary>
    Popup
}